package dockerd

import (
	"context"
	"errors"
	"fmt"
	"os"
	"time"

	"github.com/shirou/gopsutil/v3/host"

	"gopkg.openfuyao.cn/bkeadm/pkg/executor/docker"
	"gopkg.openfuyao.cn/bkeadm/pkg/global"
	"gopkg.openfuyao.cn/bkeadm/utils"
	"gopkg.openfuyao.cn/bkeadm/utils/log"
)

const (
	OverrideDockerConfig = `[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
`
)

func EnsureDockerServer(domain string, runtimeStorage string, dockerdFile string, hostIp string) (err error) {
	if ensureDockerConnect() {
		flag, err := initDockerConfig(domain, runtimeStorage)
		if err != nil {
			return err
		}
		err = configDockerTls(hostIp)
		if err != nil {
			return err
		}
		flag2 := ensureRuncVersion()
		if flag || flag2 {
			result, err := global.Command.ExecuteCommandWithCombinedOutput("systemctl", "restart", "docker")
			if err != nil {
				log.BKEFormat(log.ERROR, result)
				return err
			}
			for i := 0; i < 5; i++ {
				time.Sleep(2 * time.Second)
				if ensureDockerConnect() {
					return nil
				}
			}
		}
		return nil
	}

	log.BKEFormat(log.INFO, "install docker...")

	h, _, _, err := host.PlatformInformation()
	if err != nil {
		log.BKEFormat(log.ERROR, err.Error())
	}
	cmd := "yum"
	switch h {
	case "ubuntu", "debian":
		cmd = "apt"
	case "centos", "kylin", "redhat", "fedora":
		cmd = "yum"
	default:
		log.BKEFormat(log.WARN, "unknown platform, default yum package manger")
	}
	if h == "kylin" && utils.Exists(dockerdFile) {
		err = utils.UnTar(dockerdFile, "/")
		if err != nil {
			return err
		}
	} else {
		result, err := global.Command.ExecuteCommandWithOutput("sh", "-c", fmt.Sprintf("%s -y install docker-ce", cmd))
		if err != nil {
			log.BKEFormat(log.ERROR, result)
			return err
		}
	}

	_ = os.Mkdir("/etc/docker", 0644)
	_, err = initDockerConfig(domain, runtimeStorage)
	if err != nil {
		log.BKEFormat(log.ERROR, err.Error())
		return err
	}
	ensureRuncVersion()

	err = configDockerTls(hostIp)
	if err != nil {
		return err
	}

	if !utils.Exists("/etc/systemd/system/docker.service.d/docker.conf") {
		if !utils.Exists("/etc/systemd/system/docker.service.d") {
			err = os.MkdirAll("/etc/systemd/system/docker.service.d", 0644)
			if err != nil {
				log.BKEFormat(log.ERROR, err.Error())
				return
			}
		}
		err = os.WriteFile("/etc/systemd/system/docker.service.d/docker.conf", []byte(OverrideDockerConfig), 0644)
		if err != nil {
			log.BKEFormat(log.ERROR, err.Error())
			return
		}
	}

	result, err := global.Command.ExecuteCommandWithCombinedOutput("sh", "-c", "sudo systemctl enable docker")
	if err != nil {
		log.BKEFormat(log.WARN, fmt.Sprintf("systemctl enable docker error %s", result))
	}

	result, err = global.Command.ExecuteCommandWithCombinedOutput("sh", "-c", "sudo systemctl daemon-reload")
	if err != nil {
		log.BKEFormat(log.WARN, fmt.Sprintf("systemctl daemon-reload error %s", result))
	}

	result, err = global.Command.ExecuteCommandWithCombinedOutput("sh", "-c", "sudo systemctl start docker")
	if err != nil {
		log.BKEFormat(log.ERROR, result)
		return err
	}

	for i := 0; i < 5; i++ {
		time.Sleep(2 * time.Second)
		if ensureDockerConnect() {
			return nil
		}
	}

	return errors.New("Docker installation failed. ")
}

func ensureDockerConnect() bool {
	if global.Docker == nil {
		global.Docker, _ = docker.NewDockerClient()
	}
	if global.Docker != nil {
		_, err := global.Docker.GetClient().Ping(context.Background())
		if err == nil {
			return true
		}
	}
	return false
}
